﻿/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework
 * Version 2.10
 * 
 * Bit Splicer Class
 *		Performs bit-combination operations.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Collections;

namespace Adaptive.Foundation
{
    /// <summary>
    /// Performs bit-combination operations.
    /// </summary>
    public class BitSplicer
    {

        /*------------------------------------------------------------------------
		 * Constructor / Dispose / Destructor Methods
		 *----------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public BitSplicer()
        {
        }
        #endregion

        /*------------------------------------------------------------------------
		 * Public Methods / Functions
		 *----------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Performs a bit-combining operation on the file data.
        /// </summary>
        /// <param name="fileName">
        /// The name of the file to be operated upon.
        /// </param>
        public void SpliceDataFile(string fileName)
        {
            byte[] fileData = null;			//File data.
            byte[] leftData = null;			//Left data block.
            byte[] rightData = null;		//Right data block.
            BitArray leftBits = null;		//Left block bits.
            BitArray rightBits = null;		//Right block bits.
            BitArray bits = null;			//Combined bits.

            int count = 0;					//Iteration counter.
            int leftSize = 0;				//Size of left block.
            int rightSize = 0;				//Size of right block.
            int length = 0;					//Total data size.
            int pos = 0;					//Final bit array position.

            //Load file data into memory.
            fileData = LoadFileContent(fileName);
            if (fileData != null)
            {
                //Calculate sizes of blocks.
                length = fileData.Length;
                leftSize = (int)(fileData.Length / 2);
                rightSize = length - leftSize;

                //Create bit arrays.
                leftData = new byte[leftSize];
                rightData = new byte[rightSize];
                Array.Copy(fileData, 0, leftData, 0, leftSize);
                Array.Copy(fileData, leftSize, rightData, 0, rightSize);
                leftBits = new BitArray(leftData);
                rightBits = new BitArray(rightData);
                bits = new BitArray(length * 8);

                //Combine bit array blocks: 1st left bit + 1st right bit + 
                //2nd left bit + 2nd right bit + ...
                for (count = 0; count < leftSize * 8; count++)
                {
                    bits[pos] = leftBits[count];
                    bits[pos + 1] = rightBits[count];
                    pos += 2;
                }

                //Re-combine data.
                Array.Clear(fileData, 0, fileData.Length);
                bits.CopyTo(fileData, 0);

                //if right block is larger (fileSize == odd number), copy
                //in the last byte.
                if (rightSize > leftSize)
                    fileData[length - 1] = rightData[rightSize - 1];

                //Write data to disk.
                WriteFileContent(fileName, fileData);

                //Clear memory.
                Array.Clear(leftData, 0, leftSize);
                Array.Clear(rightData, 0, rightSize);
                Array.Clear(fileData, 0, length);
                leftBits.Length = 0;
                rightBits.Length = 0;
                bits.Length = 0;
            }

            //Clear memory.
            leftData = null;
            rightData = null;
            fileData = null;
            leftBits = null;
            rightBits = null;
            bits = null;
        }
        /// <summary>
        /// Performs a bit-decombining operation on the file data.
        /// </summary>
        /// <param name="fileName">
        /// The name of the file to be operated upon.
        /// </param>
        public void UnSpliceDataFile(string fileName)
        {
            byte[] fileData = null;			//File data.
            byte[] leftData = null;			//Left data block.
            byte[] rightData = null;		//Right data block.
            BitArray leftBits = null;		//Left block bits.
            BitArray rightBits = null;		//Right block bits.
            BitArray bits = null;			//Combined bits.

            int count = 0;					//Iteration counter.
            int leftSize = 0;				//Size of left block.
            int rightSize = 0;				//Size of right block.
            int length = 0;					//Total data size.
            int pos = 0;					//Final bit array position.

            //Load file data into memory.
            fileData = LoadFileContent(fileName);
            if (fileData != null)
            {
                //Calculate sizes of blocks.
                length = fileData.Length;
                leftSize = (int)(fileData.Length / 2);
                rightSize = length - leftSize;

                //Create bit arrays.
                leftData = new byte[leftSize];
                rightData = new byte[rightSize];
                leftBits = new BitArray(leftSize * 8);
                rightBits = new BitArray(rightSize * 8);
                bits = new BitArray(fileData);

                //DeCombine bit array blocks: 1st left bit , 1st right bit,
                //2nd left bit, 2nd right bit, ...
                for (count = 0; count < (leftSize * 8); count++)
                {
                    leftBits[count] = bits[pos];
                    rightBits[count] = bits[pos + 1];
                    pos += 2;
                }

                //Re-combine data.
                leftBits.CopyTo(leftData, 0);
                rightBits.CopyTo(rightData, 0);
                Array.Copy(leftData, 0, fileData, 0, leftSize);
                Array.Copy(rightData, 0, fileData, leftSize, rightSize);

                //if right block is larger (fileSize == odd number), copy
                //in the last byte.
                if (rightSize > leftSize)
                    fileData[length - 1] = rightData[rightSize - 1];

                //Write data to disk.
                WriteFileContent(fileName, fileData);

                //Clear memory.
                Array.Clear(leftData, 0, leftSize);
                Array.Clear(rightData, 0, rightSize);
                Array.Clear(fileData, 0, length);
                leftBits.Length = 0;
                rightBits.Length = 0;
                bits.Length = 0;
            }

            //Clear memory.
            leftData = null;
            rightData = null;
            fileData = null;
            leftBits = null;
            rightBits = null;
            bits = null;
        }
        #endregion

        /*------------------------------------------------------------------------
		 * Private Methods / Functions
		 *----------------------------------------------------------------------*/
        #region Private Methods / Functions
        /// <summary>
        /// Loads the specifie file content into memory.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private byte[] LoadFileContent(string fileName)
        {
            FileStream file = null;			//File Access object.
            BinaryReader reader = null;		//Data reader.
            byte[] returnValue = null;		//Return value.

            try
            {
                file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                reader = new BinaryReader(file);
                returnValue = reader.ReadBytes((int)file.Length);
                reader.Close();
                file.Close();
            }
            catch (System.IO.IOException)
            {
                returnValue = null;
            }

            file = null;
            reader = null;
            return returnValue;
        }
        /// <summary>
        /// Writes the specified file content to disk.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private void WriteFileContent(string fileName, byte[] content)
        {
            FileStream file = null;			//File Access object.
            BinaryWriter writer = null;		//Data writer.

            try
            {
                if (File.Exists(fileName))
                    File.Delete(fileName);
                file = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write);
                writer = new BinaryWriter(file);
                writer.Write(content);
                writer.Close();
                file.Close();
            }
            catch (IOException)
            {
            }
            writer = null;
            file = null;
        }
        #endregion
    }
}
